Scrapy de sitios con R
rm(list = ls()) # Para limpiar memoria
# Cargar librerías necesarias para reatlizar solicitudes HTTP, parseo de HTML, manipulación de datos y manejo de texto
library(httr) # Para realizar solicitudes HTTP
library(rvest) # Para extraer y parsear contenido HTML
library(dplyr) # Para manipulación de datos
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(jsonlite) # Para manejar datos JSON
library(stringr) # Para trabajar con cadenas de texto
library(openssl) # Para codificar base64
## Linking to: OpenSSL 3.0.2 15 Mar 2022
library(lubridate) # Para fechas
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
library(DT) # Para datatables en la expostacion HTML
# Definimos el número de páginas a scrapear
num_paginas <- 5
# Definimos el agente de usuario para simular una solicitud desde un navegador
agente_usuario <- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
# Función para configurar el agente de usuario en las solicitudes HTTP
configurar_agente_usuario <- function() {
httr::set_config(httr::user_agent(agente_usuario))
}
# Función para crear una lista de URLs a scrapear
# Recibe como entrada una URL base, el número de páginas y una función opcional para parámetros adicionales
crear_lista_paginas <- function(url_base, num_paginas, funcion_parametros = NULL) {
lista_urls <- vector("list", num_paginas)
# Iteramos sobre el número de páginas para generar cada URL
for (i in seq_len(num_paginas)) {
lista_urls[[i]] <- if (is.null(funcion_parametros)) {
# Si no se pasa una función para parámetros, concatenamos el número de página a la URL base
paste0(url_base, i)
} else {
# Si se pasa una función, la usamos para generar los parámetros personalizados
funcion_parametros(url_base, i)
}
}
return(lista_urls)
}
# Función para convertir un texto en un slug amigable para URLs (sin caracteres especiales)
crear_slug <- function(texto) {
texto %>%
tolower() %>% # Convertimos el texto a minúsculas
str_replace_all("[^a-z0-9]+", "-") %>% # Reemplazamos caracteres no alfanuméricos por guiones
str_replace_all("(^-|-$)", "") # Eliminamos guiones al inicio o final
}
scrapy HTML DOM, despues de ver el DOM podemos ver que hay un ajax que trae el html completo de cada pagina y tambien un json dentro del mismo html
# Función para extraer datos de una página de productos de la tienda TOTTO
extraer_datos_totto <- function(url) {
# Intentamos leer el contenido HTML de la página
documento <- tryCatch(
read_html(url, user_agent = agente_usuario),
error = function(e) {
message(paste("Error al cargar:", url)) # Mostramos un mensaje en caso de error
return(NULL) # Retornamos NULL si hay un error
}
)
if (is.null(documento)) return(NULL) # Si no se pudo cargar el documento, salimos de la función
print(paste("Extrayendo datos de:", url))
# Seleccionamos los elementos HTML que contienen los productos
productos_html <- documento %>% html_elements("div._banner-title")
# Extraemos y retornamos la información relevante de cada producto
data.frame(
url = productos_html %>% html_element("a") %>% html_attr("href"),
imagen = productos_html %>% html_element("img") %>% html_attr("src"),
nombre = productos_html %>% html_element("h3 span") %>% html_text(trim = TRUE),
precio = productos_html %>%
html_element("span.__item-price") %>%
html_text(trim = TRUE) %>%
str_replace_all("Bs. ", "") %>% # quitamos signo "Bs. "
str_replace_all("\\.", "") %>% # removemos todos los puntos por casos 1.153,00
str_replace_all(",", ".") %>% # convertimos comas en puntos
as.numeric()
,
fecha = today(),
tienda = "totto",
stringsAsFactors = FALSE
)
}
# Función para extraer datos de múltiples páginas de la tienda TOTTO
extraer_datos_sitio_totto <- function(url_base, num_paginas) {
configurar_agente_usuario() # Configuramos el agente de usuario
lista_urls <- crear_lista_paginas(url_base, num_paginas) # Creamos la lista de URLs
# Extraemos los datos de cada página y los combinamos en un solo data frame
do.call(
bind_rows,
lapply(lista_urls, extraer_datos_totto)
)
}
scrapy GraphQL, base64encode, urlencode, esta tienda cuemnta con una
recarga en “Mosrar mas Productos” que
cuando inspeccionamos parece ser un graphQL enviando parametros por GET
codificado url, procedemos a decodificar y vemos que es un json
vemos que hay otro parametro que esta encriptado posiblemente base64
por lo que decodificamos en base 64 y podemos ver otro JSON
donde apreciamos parametros de paginacion
probamos cambiando a otro rango de pagina
y
volvemos a codificar
Probamos el url en navegador y funciona
Este sitio nos permite usar parseo JSON, codificacion bas64 y url ademas de transformacion de fecha y precio
# Función para extraer datos de una página de productos de la tienda Multicenter
extraer_datos_multicenter <- function(url) {
# Intentamos realizar una solicitud GET a la URL
respuesta <- tryCatch(
GET(url, user_agent = agente_usuario),
error = function(e) {
message(paste("Error al cargar:", url)) # Mostramos un mensaje en caso de error
return(NULL) # Retornamos NULL si hay un error
}
)
if (is.null(respuesta)) return(NULL) # Si no hay respuesta, salimos de la función
print(paste("Extrayendo datos de:", url))
# Parseamos el contenido JSON de la respuesta
content <- content(respuesta, "text")
datos_json <- fromJSON(content)
# Seleccionamos los elementos JSON que contienen los productos
productos <- datos_json$data$productSearch$products
# Extraemos y retornamos la información relevante de cada producto
data.frame(
url = str_replace_all(productos$link,"portal.vtexcommercestable.com.br","www.multicenter.com"),
# imagen = productos$items[[1]]$images[[1]]$imageUrl, # FIXME - issue con imagenes
imagen = '',
nombre = productos$productName,
precio = productos$priceRange$sellingPrice$lowPrice,
fecha = productos$releaseDate %>% substr(1,10) %>% ymd(),
tienda = "multicenter",
stringsAsFactors = FALSE
)
}
# Función para extraer datos de múltiples páginas de la tienda TOTTO
extraer_datos_sitio_multicenter <- function(url_base, num_paginas) {
configurar_agente_usuario() # Configuramos el agente de usuario
# Creamos la lista de URLs con parámetros personalizados
lista_urls <- crear_lista_paginas(url_base, num_paginas, function(base, i) {
desde <- (i - 1) * 50
hasta <- i * 50
variables <-paste0(
'{"hideUnavailableItems":false,"skusFilter":"ALL","simulationBehavior":"skip","installmentCriteria":"MAX_WITHOUT_INTEREST","productOriginVtex":true,"map":"productClusterIds","query":"647","orderBy":"OrderByBestDiscountDESC","from":',
desde,
',"to":',
hasta,
',"selectedFacets":[{"key":"productClusterIds","value":"647"}],"operator":"and","fuzzy":"0","searchState":null,"facetsBehavior":"Static","categoryTreeBehavior":"default","withFacets":false,"advertisementOptions":{"showSponsored":true,"sponsoredCount":3,"advertisementPlacement":"top_search","repeatSponsoredProducts":true}}') %>%
base64_encode() # convertimos en base64
extensions<-paste0(
'{"persistedQuery":{"version":1,"sha256Hash":"9177ba6f883473505dc99fcf2b679a6e270af6320a157f0798b92efeab98d5d3","sender":"vtex.store-resources@0.x","provider":"vtex.search-graphql@0.x"},"variables":"',
variables,
'"}') %>%
URLencode(reserved = T) # codificamos el url
paste0(url_base,"?extensions=", extensions)
})
# Extraemos los datos de cada página y los combinamos en un solo data frame
do.call(
bind_rows,
lapply(lista_urls, extraer_datos_multicenter)
)
}
Scrapy JSON by urlParams - Despues de revisar el sitio del deber se puede e irnos a una categoria, podemos ver que el ver mas noticias carga un ajax con un JSON con el cual construye la visualizacion, probrando con los parametros y quitando el slug que corresponde a categoria podemos traer todas las noticias, por paginas que especifiquemos.
# Función para extraer datos de una página de noticias de El Deber
extraer_datos_deber <- function(url) {
# Intentamos realizar una solicitud GET a la URL
respuesta <- tryCatch(
GET(url, user_agent = agente_usuario),
error = function(e) {
message(paste("Error al cargar:", url)) # Mostramos un mensaje en caso de error
return(NULL) # Retornamos NULL si hay un error
}
)
if (is.null(respuesta)) return(NULL) # Si no hay respuesta, salimos de la función
print(paste("Extrayendo datos de:", url))
# Parseamos el contenido JSON de la respuesta
content <- content(respuesta, "text")
datos_json <- fromJSON(content)
# Extraemos y retornamos la información relevante de cada noticia
data.frame(
fecha = datos_json$PublicationDate %>% ymd_hms(tz = "UTC"),
titular = datos_json$Title_en,
medio = "El Deber",
url = paste0(
"https://eldeber.com.bo/",
crear_slug(datos_json$Nodes_en[1]),
"/",
datos_json$Url,
"_",
datos_json$Id
),
stringsAsFactors = FALSE
)
}
# Función para extraer datos de múltiples páginas de noticias de El Deber
extraer_datos_sitio_deber <- function(url_base, num_paginas) {
configurar_agente_usuario() # Configuramos el agente de usuario
# Creamos la lista de URLs con parámetros personalizados
lista_urls <- crear_lista_paginas(url_base, num_paginas, function(base, i) {
desde <- (i - 1) * 50
hasta <- i * 50
paste0(base, "?from=", desde, "&to=", hasta)
})
# Extraemos los datos de cada página y los combinamos en un solo data frame
do.call(
bind_rows,
lapply(lista_urls, extraer_datos_deber)
)
}
scrapy HTML DOM, Analizando el codigo vemos que la pagina esta
desarrollada en Drupal y que ingresando a una página de categoria, si
presionamos en paginador este actualiza por ajax la pagina, pero es
complicado replicar el ajax por la session. Entonces se puede abrir la
pagina en una nueva pestaña con los parametros
?q=views/ajax&page=2 los cuales podemos reutilizar
# Función para extraer datos de una página de noticias de La Prensa
extraer_datos_prensa <- function(url) {
# Intentamos leer el contenido HTML de la página
documento <- tryCatch(
read_html(url, user_agent = agente_usuario),
error = function(e) {
message(paste("Error al cargar:", url)) # Mostramos un mensaje en caso de error
return(NULL) # Retornamos NULL si hay un error
}
)
if (is.null(documento)) return(NULL) # Si no se pudo cargar el documento, salimos de la función
print(paste("Extrayendo datos de:", url))
# Seleccionamos los elementos HTML que contienen las noticias
noticias_html <- documento %>% html_elements("div.views-row")
# Extraemos y retornamos la información relevante de cada noticia
data.frame(
fecha = noticias_html %>%
html_element("time") %>%
html_attr("datetime") %>%
ymd_hms(tz = "UTC"), # convertimos a campo tipo fecha
titular = noticias_html %>% html_element("h2 a") %>% html_text(trim = TRUE),
url = paste0(
"https://laprensa.bo",
noticias_html %>% html_element("h2 a") %>% html_attr("href")
),
medio = "La Prensa",
stringsAsFactors = FALSE
)
}
# Función para extraer datos de múltiples páginas de noticias de La Prensa
extraer_datos_sitio_prensa <- function(url_base, num_paginas) {
configurar_agente_usuario() # Configuramos el agente de usuario
lista_urls <- crear_lista_paginas(url_base, num_paginas) # Creamos la lista de URLs
# Extraemos los datos de cada página y los combinamos en un solo data frame
do.call(
bind_rows,
lapply(lista_urls, extraer_datos_prensa)
)
}
Podemos ejecutar los scrapers desde aqui
# Definimos las URLs base de cada fuente
url_base_totto <- "https://bo.totto.com/buscapagina?fq=C%3a%2f82%2f&PS=48&sl=ae85c755-2e56-4945-a435-89444d09dcb2&cc=48&sm=0&PageNumber="
url_base_multicenter="https://www.multicenter.com/_v/segment/graphql/v1"
url_base_deber <- "https://eldeber.com.bo/api/news/getMore"
url_base_prensa <- "https://laprensa.bo/politica?q=views/ajax&page="
# Extraemos los datos de cada sitio
datos_productos_totto <- extraer_datos_sitio_totto(url_base_totto, num_paginas)
## [1] "Extrayendo datos de: https://bo.totto.com/buscapagina?fq=C%3a%2f82%2f&PS=48&sl=ae85c755-2e56-4945-a435-89444d09dcb2&cc=48&sm=0&PageNumber=1"
## [1] "Extrayendo datos de: https://bo.totto.com/buscapagina?fq=C%3a%2f82%2f&PS=48&sl=ae85c755-2e56-4945-a435-89444d09dcb2&cc=48&sm=0&PageNumber=2"
## [1] "Extrayendo datos de: https://bo.totto.com/buscapagina?fq=C%3a%2f82%2f&PS=48&sl=ae85c755-2e56-4945-a435-89444d09dcb2&cc=48&sm=0&PageNumber=3"
## [1] "Extrayendo datos de: https://bo.totto.com/buscapagina?fq=C%3a%2f82%2f&PS=48&sl=ae85c755-2e56-4945-a435-89444d09dcb2&cc=48&sm=0&PageNumber=4"
## [1] "Extrayendo datos de: https://bo.totto.com/buscapagina?fq=C%3a%2f82%2f&PS=48&sl=ae85c755-2e56-4945-a435-89444d09dcb2&cc=48&sm=0&PageNumber=5"
datos_productos_multicenter <- extraer_datos_sitio_multicenter(url_base_multicenter, num_paginas)
## [1] "Extrayendo datos de: https://www.multicenter.com/_v/segment/graphql/v1?extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%229177ba6f883473505dc99fcf2b679a6e270af6320a157f0798b92efeab98d5d3%22%2C%22sender%22%3A%22vtex.store-resources%400.x%22%2C%22provider%22%3A%22vtex.search-graphql%400.x%22%7D%2C%22variables%22%3A%22eyJoaWRlVW5hdmFpbGFibGVJdGVtcyI6ZmFsc2UsInNrdXNGaWx0ZXIiOiJBTEwiLCJzaW11bGF0aW9uQmVoYXZpb3IiOiJza2lwIiwiaW5zdGFsbG1lbnRDcml0ZXJpYSI6Ik1BWF9XSVRIT1VUX0lOVEVSRVNUIiwicHJvZHVjdE9yaWdpblZ0ZXgiOnRydWUsIm1hcCI6InByb2R1Y3RDbHVzdGVySWRzIiwicXVlcnkiOiI2NDciLCJvcmRlckJ5IjoiT3JkZXJCeUJlc3REaXNjb3VudERFU0MiLCJmcm9tIjowLCJ0byI6NTAsInNlbGVjdGVkRmFjZXRzIjpbeyJrZXkiOiJwcm9kdWN0Q2x1c3RlcklkcyIsInZhbHVlIjoiNjQ3In1dLCJvcGVyYXRvciI6ImFuZCIsImZ1enp5IjoiMCIsInNlYXJjaFN0YXRlIjpudWxsLCJmYWNldHNCZWhhdmlvciI6IlN0YXRpYyIsImNhdGVnb3J5VHJlZUJlaGF2aW9yIjoiZGVmYXVsdCIsIndpdGhGYWNldHMiOmZhbHNlLCJhZHZlcnRpc2VtZW50T3B0aW9ucyI6eyJzaG93U3BvbnNvcmVkIjp0cnVlLCJzcG9uc29yZWRDb3VudCI6MywiYWR2ZXJ0aXNlbWVudFBsYWNlbWVudCI6InRvcF9zZWFyY2giLCJyZXBlYXRTcG9uc29yZWRQcm9kdWN0cyI6dHJ1ZX19%22%7D"
## [1] "Extrayendo datos de: https://www.multicenter.com/_v/segment/graphql/v1?extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%229177ba6f883473505dc99fcf2b679a6e270af6320a157f0798b92efeab98d5d3%22%2C%22sender%22%3A%22vtex.store-resources%400.x%22%2C%22provider%22%3A%22vtex.search-graphql%400.x%22%7D%2C%22variables%22%3A%22eyJoaWRlVW5hdmFpbGFibGVJdGVtcyI6ZmFsc2UsInNrdXNGaWx0ZXIiOiJBTEwiLCJzaW11bGF0aW9uQmVoYXZpb3IiOiJza2lwIiwiaW5zdGFsbG1lbnRDcml0ZXJpYSI6Ik1BWF9XSVRIT1VUX0lOVEVSRVNUIiwicHJvZHVjdE9yaWdpblZ0ZXgiOnRydWUsIm1hcCI6InByb2R1Y3RDbHVzdGVySWRzIiwicXVlcnkiOiI2NDciLCJvcmRlckJ5IjoiT3JkZXJCeUJlc3REaXNjb3VudERFU0MiLCJmcm9tIjo1MCwidG8iOjEwMCwic2VsZWN0ZWRGYWNldHMiOlt7ImtleSI6InByb2R1Y3RDbHVzdGVySWRzIiwidmFsdWUiOiI2NDcifV0sIm9wZXJhdG9yIjoiYW5kIiwiZnV6enkiOiIwIiwic2VhcmNoU3RhdGUiOm51bGwsImZhY2V0c0JlaGF2aW9yIjoiU3RhdGljIiwiY2F0ZWdvcnlUcmVlQmVoYXZpb3IiOiJkZWZhdWx0Iiwid2l0aEZhY2V0cyI6ZmFsc2UsImFkdmVydGlzZW1lbnRPcHRpb25zIjp7InNob3dTcG9uc29yZWQiOnRydWUsInNwb25zb3JlZENvdW50IjozLCJhZHZlcnRpc2VtZW50UGxhY2VtZW50IjoidG9wX3NlYXJjaCIsInJlcGVhdFNwb25zb3JlZFByb2R1Y3RzIjp0cnVlfX0%3D%22%7D"
## [1] "Extrayendo datos de: https://www.multicenter.com/_v/segment/graphql/v1?extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%229177ba6f883473505dc99fcf2b679a6e270af6320a157f0798b92efeab98d5d3%22%2C%22sender%22%3A%22vtex.store-resources%400.x%22%2C%22provider%22%3A%22vtex.search-graphql%400.x%22%7D%2C%22variables%22%3A%22eyJoaWRlVW5hdmFpbGFibGVJdGVtcyI6ZmFsc2UsInNrdXNGaWx0ZXIiOiJBTEwiLCJzaW11bGF0aW9uQmVoYXZpb3IiOiJza2lwIiwiaW5zdGFsbG1lbnRDcml0ZXJpYSI6Ik1BWF9XSVRIT1VUX0lOVEVSRVNUIiwicHJvZHVjdE9yaWdpblZ0ZXgiOnRydWUsIm1hcCI6InByb2R1Y3RDbHVzdGVySWRzIiwicXVlcnkiOiI2NDciLCJvcmRlckJ5IjoiT3JkZXJCeUJlc3REaXNjb3VudERFU0MiLCJmcm9tIjoxMDAsInRvIjoxNTAsInNlbGVjdGVkRmFjZXRzIjpbeyJrZXkiOiJwcm9kdWN0Q2x1c3RlcklkcyIsInZhbHVlIjoiNjQ3In1dLCJvcGVyYXRvciI6ImFuZCIsImZ1enp5IjoiMCIsInNlYXJjaFN0YXRlIjpudWxsLCJmYWNldHNCZWhhdmlvciI6IlN0YXRpYyIsImNhdGVnb3J5VHJlZUJlaGF2aW9yIjoiZGVmYXVsdCIsIndpdGhGYWNldHMiOmZhbHNlLCJhZHZlcnRpc2VtZW50T3B0aW9ucyI6eyJzaG93U3BvbnNvcmVkIjp0cnVlLCJzcG9uc29yZWRDb3VudCI6MywiYWR2ZXJ0aXNlbWVudFBsYWNlbWVudCI6InRvcF9zZWFyY2giLCJyZXBlYXRTcG9uc29yZWRQcm9kdWN0cyI6dHJ1ZX19%22%7D"
## [1] "Extrayendo datos de: https://www.multicenter.com/_v/segment/graphql/v1?extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%229177ba6f883473505dc99fcf2b679a6e270af6320a157f0798b92efeab98d5d3%22%2C%22sender%22%3A%22vtex.store-resources%400.x%22%2C%22provider%22%3A%22vtex.search-graphql%400.x%22%7D%2C%22variables%22%3A%22eyJoaWRlVW5hdmFpbGFibGVJdGVtcyI6ZmFsc2UsInNrdXNGaWx0ZXIiOiJBTEwiLCJzaW11bGF0aW9uQmVoYXZpb3IiOiJza2lwIiwiaW5zdGFsbG1lbnRDcml0ZXJpYSI6Ik1BWF9XSVRIT1VUX0lOVEVSRVNUIiwicHJvZHVjdE9yaWdpblZ0ZXgiOnRydWUsIm1hcCI6InByb2R1Y3RDbHVzdGVySWRzIiwicXVlcnkiOiI2NDciLCJvcmRlckJ5IjoiT3JkZXJCeUJlc3REaXNjb3VudERFU0MiLCJmcm9tIjoxNTAsInRvIjoyMDAsInNlbGVjdGVkRmFjZXRzIjpbeyJrZXkiOiJwcm9kdWN0Q2x1c3RlcklkcyIsInZhbHVlIjoiNjQ3In1dLCJvcGVyYXRvciI6ImFuZCIsImZ1enp5IjoiMCIsInNlYXJjaFN0YXRlIjpudWxsLCJmYWNldHNCZWhhdmlvciI6IlN0YXRpYyIsImNhdGVnb3J5VHJlZUJlaGF2aW9yIjoiZGVmYXVsdCIsIndpdGhGYWNldHMiOmZhbHNlLCJhZHZlcnRpc2VtZW50T3B0aW9ucyI6eyJzaG93U3BvbnNvcmVkIjp0cnVlLCJzcG9uc29yZWRDb3VudCI6MywiYWR2ZXJ0aXNlbWVudFBsYWNlbWVudCI6InRvcF9zZWFyY2giLCJyZXBlYXRTcG9uc29yZWRQcm9kdWN0cyI6dHJ1ZX19%22%7D"
## [1] "Extrayendo datos de: https://www.multicenter.com/_v/segment/graphql/v1?extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%229177ba6f883473505dc99fcf2b679a6e270af6320a157f0798b92efeab98d5d3%22%2C%22sender%22%3A%22vtex.store-resources%400.x%22%2C%22provider%22%3A%22vtex.search-graphql%400.x%22%7D%2C%22variables%22%3A%22eyJoaWRlVW5hdmFpbGFibGVJdGVtcyI6ZmFsc2UsInNrdXNGaWx0ZXIiOiJBTEwiLCJzaW11bGF0aW9uQmVoYXZpb3IiOiJza2lwIiwiaW5zdGFsbG1lbnRDcml0ZXJpYSI6Ik1BWF9XSVRIT1VUX0lOVEVSRVNUIiwicHJvZHVjdE9yaWdpblZ0ZXgiOnRydWUsIm1hcCI6InByb2R1Y3RDbHVzdGVySWRzIiwicXVlcnkiOiI2NDciLCJvcmRlckJ5IjoiT3JkZXJCeUJlc3REaXNjb3VudERFU0MiLCJmcm9tIjoyMDAsInRvIjoyNTAsInNlbGVjdGVkRmFjZXRzIjpbeyJrZXkiOiJwcm9kdWN0Q2x1c3RlcklkcyIsInZhbHVlIjoiNjQ3In1dLCJvcGVyYXRvciI6ImFuZCIsImZ1enp5IjoiMCIsInNlYXJjaFN0YXRlIjpudWxsLCJmYWNldHNCZWhhdmlvciI6IlN0YXRpYyIsImNhdGVnb3J5VHJlZUJlaGF2aW9yIjoiZGVmYXVsdCIsIndpdGhGYWNldHMiOmZhbHNlLCJhZHZlcnRpc2VtZW50T3B0aW9ucyI6eyJzaG93U3BvbnNvcmVkIjp0cnVlLCJzcG9uc29yZWRDb3VudCI6MywiYWR2ZXJ0aXNlbWVudFBsYWNlbWVudCI6InRvcF9zZWFyY2giLCJyZXBlYXRTcG9uc29yZWRQcm9kdWN0cyI6dHJ1ZX19%22%7D"
# Combinamos las tiendas de las distintas fuentes en un solo data frame
datos_productos <- bind_rows(datos_productos_totto, datos_productos_multicenter)
datos_noticias_deber <- extraer_datos_sitio_deber(url_base_deber, num_paginas)
## [1] "Extrayendo datos de: https://eldeber.com.bo/api/news/getMore?from=0&to=50"
## [1] "Extrayendo datos de: https://eldeber.com.bo/api/news/getMore?from=50&to=100"
## [1] "Extrayendo datos de: https://eldeber.com.bo/api/news/getMore?from=100&to=150"
## [1] "Extrayendo datos de: https://eldeber.com.bo/api/news/getMore?from=150&to=200"
## [1] "Extrayendo datos de: https://eldeber.com.bo/api/news/getMore?from=200&to=250"
datos_noticias_prensa <- extraer_datos_sitio_prensa(url_base_prensa, num_paginas)
## [1] "Extrayendo datos de: https://laprensa.bo/politica?q=views/ajax&page=1"
## [1] "Extrayendo datos de: https://laprensa.bo/politica?q=views/ajax&page=2"
## [1] "Extrayendo datos de: https://laprensa.bo/politica?q=views/ajax&page=3"
## [1] "Extrayendo datos de: https://laprensa.bo/politica?q=views/ajax&page=4"
## [1] "Extrayendo datos de: https://laprensa.bo/politica?q=views/ajax&page=5"
# Combinamos las noticias de las distintas fuentes en un solo data frame
datos_noticias <- bind_rows(datos_noticias_deber, datos_noticias_prensa)
# Guardamos los datos extraídos en un archivo
save(datos_productos, datos_noticias, file = "_data/datos_scrapeados.RData")
# Mostrar las tablas generadas
str(datos_productos)
## 'data.frame': 490 obs. of 6 variables:
## $ url : chr "https://bo.totto.com/mochila-rayol/p?idsku=32066" "https://bo.totto.com/mochila-acuarela/p?idsku=32046" "https://bo.totto.com/mochila-porta-portatil-daki-ma04ind909-23100-z3g/p?idsku=28429" "https://bo.totto.com/mochila-titanio-20/p?idsku=33102" ...
## $ imagen: chr "https://tottobo.vteximg.com.br/arquivos/ids/284347-292-292/MA04ECO002-2326N-4DR_2.jpg?v=638362967867130000" "https://tottobo.vteximg.com.br/arquivos/ids/284264-292-292/MA04ECO001-23260-4DR_2.jpg?v=638362957156730000" "https://tottobo.vteximg.com.br/arquivos/ids/275084-292-292/MA04IND909-23100-Z3G-ECOMMERCE_1.jpg?v=638240997571900000" "https://tottobo.vteximg.com.br/arquivos/ids/289570-292-292/MA04TEK004-2410G-NV0_1.jpg?v=638497569558700000" ...
## $ nombre: chr "Mochila Rayol" "Mochila Acuarela" "Mochila Porta Portátil Daki" "Mochila Titanio 2.0" ...
## $ precio: num 519 479 719 849 679 899 889 859 290 699 ...
## $ fecha : Date, format: "2024-12-09" "2024-12-09" ...
## $ tienda: chr "totto" "totto" "totto" "totto" ...
head(datos_productos)
## url
## 1 https://bo.totto.com/mochila-rayol/p?idsku=32066
## 2 https://bo.totto.com/mochila-acuarela/p?idsku=32046
## 3 https://bo.totto.com/mochila-porta-portatil-daki-ma04ind909-23100-z3g/p?idsku=28429
## 4 https://bo.totto.com/mochila-titanio-20/p?idsku=33102
## 5 https://bo.totto.com/mochila-molyk/p?idsku=32116
## 6 https://bo.totto.com/mochila-rue-bomper-soccer-win-m/p?idsku=31746
## imagen
## 1 https://tottobo.vteximg.com.br/arquivos/ids/284347-292-292/MA04ECO002-2326N-4DR_2.jpg?v=638362967867130000
## 2 https://tottobo.vteximg.com.br/arquivos/ids/284264-292-292/MA04ECO001-23260-4DR_2.jpg?v=638362957156730000
## 3 https://tottobo.vteximg.com.br/arquivos/ids/275084-292-292/MA04IND909-23100-Z3G-ECOMMERCE_1.jpg?v=638240997571900000
## 4 https://tottobo.vteximg.com.br/arquivos/ids/289570-292-292/MA04TEK004-2410G-NV0_1.jpg?v=638497569558700000
## 5 https://tottobo.vteximg.com.br/arquivos/ids/285082-292-292/MA04IND920-23200-B04_1.jpg?v=638362989098300000
## 6 https://tottobo.vteximg.com.br/arquivos/ids/284967-292-292/MJ03SOW005-2320-7J8M_1.jpg?v=638362986707200000
## nombre precio fecha tienda
## 1 Mochila Rayol 519 2024-12-09 totto
## 2 Mochila Acuarela 479 2024-12-09 totto
## 3 Mochila Porta Portátil Daki 719 2024-12-09 totto
## 4 Mochila Titanio 2.0 849 2024-12-09 totto
## 5 Mochila Molyk 679 2024-12-09 totto
## 6 Mochila Rue Bomper Soccer Win M 899 2024-12-09 totto
datatable(datos_productos)
str(datos_noticias)
## 'data.frame': 800 obs. of 4 variables:
## $ fecha : POSIXct, format: "2024-12-09 22:40:49" "2024-12-09 22:38:07" ...
## $ titular: chr "Alcalde de La Paz se defenderá en libertad en el caso 'Bajo Llojeta'" "Cuatro clubes brillaron en el Nacional Preinfantil e Infantil Clausura de Natación" "Bolivia registra 26 casos de tosferina en lo que va del año" "Trudeau sobrevive a la tercera moción de censura presentada por los conservadores" ...
## $ medio : chr "El Deber" "El Deber" "El Deber" "El Deber" ...
## $ url : chr "https://eldeber.com.bo/pa-s/alcalde-de-la-paz-se-defendera-en-libertad-en-el-caso-bajo-llojeta_394611" "https://eldeber.com.bo/pa-s/cuatro-clubes-brillaron-en-el-nacional-preinfantil-e-infantil-clausura-de-natacion_394616" "https://eldeber.com.bo/pa-s/bolivia-registra-26-casos-de-tosferina-en-lo-que-va-del-ano_394615" "https://eldeber.com.bo/pa-s/trudeau-sobrevive-a-la-tercera-mocion-de-censura-presentada-por-los-conservadores_394614" ...
head(datos_noticias)
## fecha
## 1 2024-12-09 22:40:49
## 2 2024-12-09 22:38:07
## 3 2024-12-09 22:24:00
## 4 2024-12-09 22:06:00
## 5 2024-12-09 22:03:07
## 6 2024-12-09 21:53:00
## titular
## 1 Alcalde de La Paz se defenderá en libertad en el caso 'Bajo Llojeta'
## 2 Cuatro clubes brillaron en el Nacional Preinfantil e Infantil Clausura de Natación
## 3 Bolivia registra 26 casos de tosferina en lo que va del año
## 4 Trudeau sobrevive a la tercera moción de censura presentada por los conservadores
## 5 Víctor Muriel, campeón de la Copa Simón Bolívar Femenina de Futsal
## 6 Nallar cumple sentencia aislado en un pabellón de máxima seguridad de Palmasola
## medio
## 1 El Deber
## 2 El Deber
## 3 El Deber
## 4 El Deber
## 5 El Deber
## 6 El Deber
## url
## 1 https://eldeber.com.bo/pa-s/alcalde-de-la-paz-se-defendera-en-libertad-en-el-caso-bajo-llojeta_394611
## 2 https://eldeber.com.bo/pa-s/cuatro-clubes-brillaron-en-el-nacional-preinfantil-e-infantil-clausura-de-natacion_394616
## 3 https://eldeber.com.bo/pa-s/bolivia-registra-26-casos-de-tosferina-en-lo-que-va-del-ano_394615
## 4 https://eldeber.com.bo/pa-s/trudeau-sobrevive-a-la-tercera-mocion-de-censura-presentada-por-los-conservadores_394614
## 5 https://eldeber.com.bo/pa-s/victor-muriel-campeon-de-la-copa-simon-bolivar-femenina-de-futsal_394613
## 6 https://eldeber.com.bo/pa-s/nallar-cumple-sentencia-aislado-en-un-pabellon-de-maxima-seguridad-de-palmasola_394612
datatable(datos_noticias)